package cn.onlinecache.breakpad;

import android.app.Application;
import android.os.Environment;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;


public class NativeBreakpad implements Thread.UncaughtExceptionHandler {
    private static final String TAG = "NativeBreakpad";

    private static final String FILE_NAME = "crash";

    private static final String FILE_NAME_SUFFIX = ".trace";

    private static boolean loadBreakpadSuccess = false;

    private Application mContext;
    private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
    private String dir;


    private static NativeBreakpad instance = new NativeBreakpad();

    static {
        try {
            System.loadLibrary("breakpad");
            loadBreakpadSuccess = true;
        } catch (Exception e) {
            loadBreakpadSuccess = false;
            Log.e(TAG, "fail to load breakpad");
        }
    }

    public static NativeBreakpad getInstance() {
        return instance;
    }

    public void init(Application application) {
        mContext = application;
        String logs = null;
        try {
            if ((Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                    || !Environment.isExternalStorageRemovable()) && mContext.getExternalCacheDir() != null) {
                logs = mContext.getExternalCacheDir().getPath();
            } else {
                logs = mContext.getCacheDir().getPath();
            }

            logs += "/logs/";
            File file = new File(logs);
            if (!file.exists()) {
                file.mkdirs();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        dir = logs;
        initJava();
        initNative();
    }

    private boolean initNative() {
        if (TextUtils.isEmpty(dir)) {
            Log.e(TAG, "dumpFileDir can not be empty");
            loadBreakpadSuccess = false;
            return false;
        }
        return loadBreakpadSuccess && nativeInit(dir) > 0;
    }

    private static native int nativeInit(String dumpFileDir);

    private static native int nativeTestCrash();

    public int testNativeCrash() {
        if (loadBreakpadSuccess) {
            Log.d(TAG, "test native crash .......................");
            return nativeTestCrash();
        }
        return -1;
    }


    private void initJava() {
        mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        try {
            dumpExceptionToSDCard(ex);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (mDefaultCrashHandler != null) {
            mDefaultCrashHandler.uncaughtException(thread, ex);
        } else {
            Process.killProcess(Process.myPid());
        }

    }

    private void dumpExceptionToSDCard(Throwable ex) throws IOException {

        long current = System.currentTimeMillis();
        String time = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(new Date(current));

        File file = new File(dir + FILE_NAME + time + FILE_NAME_SUFFIX + Math.random());
        try {
            file.createNewFile();
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(time);
            pw.println();
            ex.printStackTrace(pw);
            pw.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "dump crash info failed " + file.getAbsolutePath());
        }
    }


}
